const expactedToken = [
  { type: "paren", value: "(" },
  { type: "name", value: "add" },
  { type: "number", value: "2" },
  { type: "paren", value: "(" },
  { type: "name", value: "subtract" },
  { type: "number", value: "4" },
  { type: "number", value: "2" },
  { type: "paren", value: ")" },
  { type: "paren", value: ")" }
];

const xxast = {
  type: "Program",
  body: [
    {
      type: "CallExpression",
      name: "add",
      params: [
        {
          type: "NumberLiteral",
          value: "2"
        },
        {
          type: "CallExpression",
          name: "subtract",
          params: [
            {
              type: "NumberLiteral",
              value: "4"
            },
            {
              type: "NumberLiteral",
              value: "2"
            }
          ]
        }
      ]
    }
  ]
};

function xparser(tokens) {
    let current = 0;
    function walk () {
        let token = tokens[current];
        
        if (token.type === 'number') {
            current++;
            return {
                type: 'NumberLiteral',
                value: token.value
            }
        }
        
        if (token === 'string') {
            current++;
            return {
                type: 'StringLiteral',
                value: token.value
            }
        }

        if (token.type === 'paren' && token.value === '(') {
            token = tokens[++current]
            let node = {
                type: 'CallExpression',
                name: token.value,
                params: [],
            }
            token = tokens[++current];
            while ((token.type !== 'paren') || (token.type ==='paren' && token.value !== ')')) {
                node.params.push(walk());
                token = tokens[current];
            }
            current++;
            return node;
        }

        throw new TypeError(token.type)

    }
    let ast = {
        type: 'Program',
        body: [],
    }

    while (current < tokens.length) {
        ast.body.push(walk());
    }

    return ast;
}


function parser(tokens) {
    let current = 0;
    let ast = {
        type: 'Program',
        body: [],
    }
    function walk () {
        let token = tokens[current];
        if (token.type === 'string') {
            current++;
            return {
                type: 'StringLiteral',
                value: token.value
            }
        }
        if (token.type === 'number') {
            current++;
            return {
                type: 'NumberLiteral',
                value: token.value
            }
        }
        if (token.value === '(') {
            token = tokens[++current]
            let node = {
                type: 'CallExpress',
                name: token.name,
                params: []
            }
            token = tokens[++current]
            while (token.value !== ')') {
                node.params.push(walk())
                token = tokens[current]
            }
            current++
            return node;
        }
        throw TypeError(token.type)
    }
    ast.body.push(walk())
    return ast
}
console.log(JSON.stringify(parser(expactedToken),null, 2));